package de.tabuma.soap;

import de.tabuma.soap.annotation.*;
import de.tabuma.soap.entity.wsdl.*;
import de.tabuma.soap.entity.xsd.*;
import de.tabuma.soap.logik.*;

import java.io.*;
import java.net.*;
import java.util.*;
import java.lang.reflect.*;

import org.xml.sax.*;
import org.xml.sax.helpers.*;

import java.util.logging.*;

/**
 * Handler for integrating soap messages.
 * @author $Author: alefen $
 * @version $Revision: 1.1 $
 * @since $Date: 2009/12/30 02:53:55 $
 */
public class SoapHandler implements org.xml.sax.ContentHandler {

    private static final Logger log = Logger.getLogger(SoapHandler.class.getName());

    String url;
    Vector<Object> objectList;
    Class className;

    public SoapHandler(URL url) {
        try {
            URLConnection conn = url.openConnection();
            objectList = new Vector<Object>();
            XMLReader parser = XMLReaderFactory.createXMLReader();
            parser.setContentHandler(this);
            
            InputSource myInputSource = new InputSource(conn.getInputStream());
            parser.parse(myInputSource);
            this.url = url.getFile();
        }
        catch(Exception e) {
            log.warning(e.getMessage());
            String warning = "";
            for(int i=0;i<e.getStackTrace().length;i++) {
                warning += e.getStackTrace()[i].toString()+"\n";
            }
            log.warning(warning);
        }
    }

    public SoapHandler(File url) {
        try {
            objectList = new Vector<Object>();
            XMLReader parser = XMLReaderFactory.createXMLReader();
            parser.setContentHandler(this);

            InputSource myInputSource = new InputSource(new FileInputStream(url));
            parser.parse(myInputSource);
            this.url = url.getAbsolutePath();

        }
        catch(Exception e) {
            log.warning(e.getMessage());
        }
    }

    private Object parserState;
    public TDefinitions toWsdlObject() throws ClassCastException {
        return (TDefinitions) parserState;
    }

    public XsSchema toXsdObject() throws ClassCastException {
        return (XsSchema) parserState;
    }

    public void characters(char[] ch, int start, int length) throws SAXException {
        String str = String.valueOf(ch).substring(start, start+length);
        str = str.replaceAll("\t", "");
        str = str.replaceAll("\n", "");
        str = str.replaceAll("  ", "");
        if(str.length()>1) {
            try {
                Field fieldList[] = parserState.getClass().getDeclaredFields();
                for(int i=0;i<fieldList.length;i++) {
                    Field field = fieldList[i];
                    log.warning(field.getName());
                    SoapAttribute soapAttribute = field.getAnnotation(SoapAttribute.class);
                    if(soapAttribute!=null) {
                        if(soapAttribute.content()) {
                            log.warning("content");
                            String methName = ObjectMethods.getSetter(field.getName());
                            Method meth = parserState.getClass().getMethod(methName, String.class);
                            meth.invoke(parserState, str);
                            PMF.doUpdate(parserState);
                            log.warning("succesfully set "+parserState);
                        }
                    }
                }
            }
            catch(Exception e) {
                log.warning(e.getMessage()+"/"+e.getCause()+"/"+e.getCause());
            }
        }
    }

    public void startDocument() throws SAXException {
        log.finest("Start parsing");
    }

    public void endDocument() throws SAXException {
        log.finest("End parsing");
    }

    public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
        if(this.parserState==null) {
            parserState = ObjectElementFacade.getObject(localName, uri, qName, parserState);
            objectList.add(parserState);
            if(parserState instanceof XsSchema) {
                if(((XsSchema)parserState).getId1()==null) {
                    PMF.doCreate(parserState);
                }
            }
            ObjectAttributeFacade.setAttributes(atts, parserState);
            if(parserState instanceof TDefinitions) {
                ((TDefinitions)parserState).setUrl(url);
            }
            log.fine(this.getWhiteSpace()+"<"+localName+" uri=\""+uri+"\">");
        }
        else {
            parserState = ObjectElementFacade.getObject(localName, uri, qName, parserState);
            ObjectAttributeFacade.setAttributes(atts, parserState);
            objectList.add(parserState);
            log.fine(this.getWhiteSpace()+"<"+localName+" uri=\""+uri+"\" head=\""+objectList.get(objectList.size()-2).getClass().getSimpleName()+"\">");
        }
    }

    public void endElement(String uri, String localName, String qName) throws SAXException {
        log.fine(this.getWhiteSpace()+"</"+localName+" class=\""+parserState.getClass().getSimpleName()+"\">");
        if(this.objectList.size()>1) {
            objectList.removeElementAt(this.objectList.size()-1);
            this.parserState = objectList.elementAt(this.objectList.size()-1);
        }
    }

    public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
        //
    }

    public void processingInstruction(String target, String data) throws SAXException {
        //
    }

    public void setDocumentLocator(Locator locator) {
        //
    }

    public void skippedEntity(String name) throws SAXException {
        //
    }

    public void startPrefixMapping(String prefix, String uri) throws SAXException {
        log.finest("start prefix mapping:"+prefix);
    }

    public void endPrefixMapping(String prefix) throws SAXException {
        log.finest("end prefix mapping:"+prefix);
    }

    public String getWhiteSpace() {
        String str = "";
        for(int i=0;i<this.objectList.size();i++) {
            str += "   ";
        }
        return str;
    }
}